package com.pamakids.audio;

import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.util.Log;
import com.adobe.fre.*;

import java.io.*;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by kc2ong on 14-5-28.
 */
public class AudioContext extends FREContext {

    public static final String TAG = "AudioContext";
    //=====================================================
    /*交互命令*/
    public static final String START_RECORD = "startRecord";
    public static final String PAUSE_RECORD = "pauseRecord";
    public static final String RESUME_RECORD = "resumeRecord";
    public static final String STOP_RECORD = "stopRecord";
	public static final String CANCEL_RECORD = "cancelRecord";
    public static final String PLAY_AMR = "playAmr";
    public static final String STOP_AMR = "stopAmr";
    public static final String TO_AMR = "toAmr";
    public static final String TO_MP3 = "toMp3";
    //===================================================
    private MediaPlayer _mPlayer;
    private MediaRecorder _mRecorder;
    private String _mFilePath;
    private File _file;
    private ArrayList<String> tempFiles;
    private String sampleRate;

    @Override
    public Map<String, FREFunction> getFunctions() {
        Map<String, FREFunction> functions = new HashMap<String, FREFunction>();
        functions.put( START_RECORD, new StartRecord());
        functions.put( STOP_RECORD, new StopRecord());
		functions.put( PAUSE_RECORD, new PauseRecord());
		functions.put( RESUME_RECORD, new ResumeRecord());
		functions.put( CANCEL_RECORD, new CancelRecord());
        functions.put( PLAY_AMR, new PlayAmr());
        functions.put( STOP_AMR, new StopAmr());
        functions.put( TO_AMR, new ToAMR());
        functions.put( TO_MP3, new ToMP3());
        return functions;
    }

    @Override
    public void dispose() {
        Log.d(TAG, "AudioContext disposed!");
    }

    private void initRecorder() {
        _mRecorder = new MediaRecorder();
        _mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        _mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
        _mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        _mRecorder.setAudioSamplingRate(Integer.parseInt(sampleRate));
        Log.d(TAG, "_mRecorder_initialized !");
    }

    public void startRecord(String saveName, String formatIndex, String sampleRate) {

        if(tempFiles != null)
            return;

        this.sampleRate = sampleRate;

        if(_mFilePath == null) {
            _mFilePath = this.getActivity().getApplication().getApplicationContext()
                    .getCacheDir().getAbsolutePath();
        }

        String fileName = saveName + ".amr";

        _file = new File(_mFilePath, fileName);
        //碎片语音文件存储
        tempFiles = new ArrayList<String>();

        Log.d( TAG, "startRecord, fileName = " + fileName);
        startRecordHandler();
    }

    private void startRecordHandler() {

        Log.d(TAG, "startRecordHandler() --> called!");

        if(_mRecorder == null)
            initRecorder();
        //生成临时存储路径
        Log.d(TAG, "生成碎片文件");

        File file = new File(_mFilePath, String.valueOf(tempFiles.size()) + ".amr");
        _mRecorder.setOutputFile( file.getAbsolutePath() );
        //将碎片语音文件加入队列
        tempFiles.add(file.getAbsolutePath());
        Log.d(TAG, "碎片文件路径：" + file.getAbsolutePath());
        Log.d(TAG, "碎片文件长度：" + tempFiles.size());
         try {
            _mRecorder.prepare();
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG, "_mRecorder.prepare() error!");
        }

        _mRecorder.start();
        Log.d(TAG, "录音开始！");
    }

    private void stopRecordHandler() {
        Log.d(TAG, "stopRecordHandler() called!");
        Log.d(TAG, "录音停止, file path = " + tempFiles.get(tempFiles.size() - 1));
        if(_mRecorder != null){
            _mRecorder.stop();
            _mRecorder.reset();
            _mRecorder.release();
            _mRecorder = null;
        }
    }

    public void stopRecord() {
        Log.d(TAG, "stopRecord() --> called!");
        stopRecordHandler();
        mergeTempFiles();
        dispatchStatusEventAsync("stoped", _file.getAbsolutePath());
    }

    private void mergeTempFiles() {

        Log.d(TAG, "mergeTempFiles() --> called!");

        FileOutputStream fileOutputStream = null;
        if (!_file.exists()){
            try {
                _file.createNewFile();
                Log.d(TAG, "创建目标文件：_file");
            }catch (IOException e){
                e.printStackTrace();
                Log.d(TAG, "创建目标文件_file失败！");
            }
        }

        try {
            fileOutputStream = new FileOutputStream(_file);
            //合并碎片文件
            Log.d(TAG, "合并碎片录音文件，碎片文件数量：" + String.valueOf( tempFiles.size()));
            for(int i=0; i<tempFiles.size(); i++){
                File file = new File(tempFiles.get(i));
                FileInputStream fileInputStream = new FileInputStream(file);
                byte[] tempByte = new byte[fileInputStream.available()];

                int length = tempByte.length;
                int position = i==0 ? 0 : 6;

                while (fileInputStream.read(tempByte) != -1){
                    fileOutputStream.write(tempByte, position, length-position);
                }

                fileOutputStream.flush();
                fileInputStream.close();

                Log.d(TAG, "_file文件长度为：" + _file.length());
            }
            //关闭流
            fileOutputStream.close();
            Log.d(TAG, "_file文件最终字节长度：" + _file.length());

        }catch (IOException e){
            e.printStackTrace();
            Log.d(TAG, "mergeTempFiles 失败！");
        }

        Log.d(TAG, "删除temps文件！");
        deleteTempFiles();
    }

    private void deleteTempFiles() {
        Log.d(TAG, "deleteTempFiles() --> called!");
        for(int i = 0; i<tempFiles.size(); i++){
            File file = new File(tempFiles.get(i));
            if(file.exists())
                file.delete();
        }
        tempFiles.clear();
        tempFiles = null;
        Log.d(TAG, "删除tempFiles文件完成！");
    }

	public void pauseRecord() {
        Log.d(TAG, "pauseRecord() --> called!");
        if(_mRecorder == null)
            return;
        stopRecordHandler();
        dispatchStatusEventAsync("paused", tempFiles.get(tempFiles.size()-1));
        Log.d(TAG, "paused事件已派发！");
	}
	
	public void resumeRecord() {
        Log.d(TAG, "resumeRecord() --> called!");
        if(_mRecorder != null)
            return;
        startRecordHandler();
        dispatchStatusEventAsync("resumed", tempFiles.get(tempFiles.size()-1));
        Log.d(TAG, "resumed事件已派发！");
	}
	
	public void cancelRecord() {
        Log.d(TAG, "cancelRecord() --> called!");
        if(tempFiles == null)
            return;
        stopRecordHandler();
        deleteTempFiles();
        _file = null;
        dispatchStatusEventAsync("canceled", "");
	}

    public void toMp3() {

        Log.d(TAG, "toMp3() --> called!");
        if (_file !=null)
        {
            dispatchStatusEventAsync("mp3_converted", _file.getAbsolutePath());
            _file = null;
        }
    }

    public void toAmr() {

        Log.d(TAG, "toAmr() --> called!");
        if (_file !=null){
            dispatchStatusEventAsync("amrConverted", _file.getAbsolutePath());
            _file = null;
        }

        Log.d(TAG, "amrConverted事件已派发！");
    }

    /**
     * @path amr file path
     * @volume amr player volume
     */
    public void playAmr(String path, String volume) {
        File f = new File(path);
        Float v = Float.valueOf(volume);

        Log.d(TAG, "_mPlayer dataSource = " + f.getAbsolutePath());
        Log.d(TAG, "_mPlayer volume = " + v);

        try{
            _mPlayer = creatMediaPlay(f, v);
            _mPlayer.start();
        }catch (IOException e)
        {
            Log.d(TAG, e.getMessage());
        }
    }

    private MediaPlayer creatMediaPlay(File file, Float v) throws IOException {

        MediaPlayer m = new MediaPlayer();
        m.setOnCompletionListener(onCompletionListener);
        m.setOnErrorListener(onErrorListener);

        FileInputStream inputStream = new FileInputStream(file);
        m.setDataSource(inputStream.getFD());

        m.setVolume( v, v );
        m.prepare();
        return m;
    }

    private MediaPlayer.OnCompletionListener onCompletionListener = new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {

            Log.d(TAG, "playAmr completed!");
            mediaPlayer.pause();
            mediaPlayer.reset();
            mediaPlayer.release();
            dispatchStatusEventAsync("amrPlayCompleted", "");
        }
    };

    private MediaPlayer.OnErrorListener onErrorListener = new MediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(MediaPlayer mediaPlayer, int i, int i2) {

            Log.d(TAG, "onError: " + String.valueOf(i) + "_" + String.valueOf(i2));
            dispatchStatusEventAsync("MediaPlayer Error", String.valueOf(i) + "_" + String.valueOf(i2));
            return true;
        }
    };

    public void stopAmr() {

        Log.d(TAG, "stopAmr()！");

        if(_mPlayer!=null)
        {
            if(_mPlayer.isPlaying())
            {
                _mPlayer.stop();
            }
            _mPlayer.reset();
            _mPlayer.release();
            _mPlayer = null;
        }
        dispatchStatusEventAsync( "amrPlayCompleted", "" );
    }
}


class StartRecord implements FREFunction {

    private static final String TAG = "StartRecord";

    @Override
    public FREObject call(FREContext freContext, FREObject[] freObjects) {

        AudioContext context = (AudioContext) freContext;

        String fileName, formatIndex, sampleRate;

        try {

            fileName = freObjects[0].getAsString();
            formatIndex = freObjects[1].getAsString();
            sampleRate = freObjects[2].getAsString();
            context.startRecord(fileName, formatIndex, sampleRate);

        } catch (FRETypeMismatchException e) {
            e.printStackTrace();
        } catch (FREInvalidObjectException e) {
            e.printStackTrace();
        } catch (FREWrongThreadException e) {
            e.printStackTrace();
        }
        return null;
    }
}

class StopRecord implements FREFunction {
    @Override
    public FREObject call(FREContext freContext, FREObject[] freObjects) {
        AudioContext context = (AudioContext) freContext;
        context.stopRecord();
        return null;
    }
}

class PauseRecord implements FREFunction {
	@Override
	public FREObject call(FREContext freContext, FREObject[] freObjects) {
		AudioContext context = (AudioContext) freContext;
		context.pauseRecord();
        return null;
	}
}

class ResumeRecord implements FREFunction {
	@Override
	public FREObject call(FREContext freContext, FREObject[] freObjects) {
		AudioContext context = (AudioContext) freContext;
		context.resumeRecord();
        return null;
	}
}

class CancelRecord implements FREFunction {
	@Override
	public FREObject call(FREContext freContext, FREObject[] freObjects) {
		AudioContext context = (AudioContext) freContext;
		context.cancelRecord();
        return null;
	}
}

class StopAmr implements FREFunction {
    @Override
    public FREObject call(FREContext freContext, FREObject[] freObjects) {
        AudioContext context = (AudioContext) freContext;
        context.stopAmr();
        return null;
    }
}

class PlayAmr implements FREFunction {

    private static final String TAG = "PlayAmr";

    @Override
    public FREObject call(FREContext freContext, FREObject[] freObjects) {

        Log.d(TAG, "PlayAmr");

        AudioContext context = (AudioContext) freContext;
        try {
            String filePath = freObjects[0].getAsString();
            String volume = freObjects[1].getAsString();
            context.playAmr(filePath, volume);
        } catch (FRETypeMismatchException e) {
            e.printStackTrace();
            Log.d(TAG, e.getMessage());
        } catch (FREInvalidObjectException e) {
            e.printStackTrace();
            Log.d(TAG, e.getMessage());
        } catch (FREWrongThreadException e) {
            e.printStackTrace();
            Log.d(TAG, e.getMessage());
        }
        return null;
    }
}

class ToMP3 implements FREFunction {

    private static final String TAG = "toMp3";
    @Override
    public FREObject call(FREContext freContext, FREObject[] freObjects) {
        AudioContext context = (AudioContext) freContext;
        context.toMp3();
        return null;
    }
}

class ToAMR implements FREFunction {

    private static final String TAG = "toAmr";
    @Override
    public FREObject call(FREContext freContext, FREObject[] freObjects) {
        AudioContext context = (AudioContext) freContext;
        context.toAmr();
        return null;
    }
}